from tkinter import filedialog
from pathlib import Path
from time import sleep
import os
import random
import time
import platform

import shutil
import hashlib

def func_process_index(_long : int,_index : int):
    return "0" * _index + "1"+ "0" * (_long - _index - 1)
    
def func_calculate_md5(data):
    """
    计算字符串或文件的MD5哈希值
    :param data: 可以是字符串或文件路径
    :return: MD5哈希字符串
    """
    md5 = hashlib.md5()

    if isinstance(data, str) and os.path.isfile(data):
        # 处理文件
        with open(data, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), b''):
                md5.update(chunk)
    else:
        # 处理字符串
        if isinstance(data, str):
            data = data.encode('utf-8')
        md5.update(data)

    return md5.hexdigest()


def func_read_csv_file_to_list(_filepath: str):
    """
    获取csv文件信息
    :return: 文件信息
    """
    encodings = ['utf-8', 'gbk', 'gb18030', 'big5', 'latin1']  # 尝试的编码顺序

    for encoding in encodings:
        try:
            with open(_filepath, "r", encoding=encoding) as file:
                r = []
                for line in file.readlines():
                    line = line.strip()
                    bool_in_quote = False
                    str_tmp = ""
                    temp = []

                    for char in line:
                        if char == "\"":
                            bool_in_quote = not bool_in_quote
                        elif bool_in_quote == False and (char == "," or char == ":"):
                            temp.append(str_tmp)
                            str_tmp = ""
                        else:
                            str_tmp += char
                    if str_tmp != "":
                        temp.append(str_tmp)

                    r.append(temp)
                return r
        except UnicodeDecodeError:
            continue

    raise ValueError(f"无法解码文件 {_filepath}，尝试的编码都不适用")

def func_write_csv_file(_filepath: str, _info: list):
    with open(_filepath, "w", encoding="gbk") as file:
        for line in _info:
            # 处理每个字段，如果包含逗号则用引号包围
            formatted_line = []
            for item in line:
                if isinstance(item, str) and ',' in item:
                    formatted_line.append(f'"{item}"')
                else:
                    formatted_line.append(str(item))
            file.write(','.join(formatted_line) + '\n')


def func_get_value_by_key(_seq: list, _key: str):
    try:
        for item in _seq:
            if _key == item[0]:
                return item[1::]
        return None
    except:
        return None


def func_remove_value_by_key(_seq: list, _key: str):
    try:
        for i in range(len(_seq)):
            if _key == _seq[i][0]:
                return _seq[0:i] + _seq[i + 1:]
        return _seq
    except:
        return _seq


def func_change_value(_seq: list, _new: list):
    try:
        for i in range(len(_seq)):
            if _new[0] == _seq[i][0]:
                _seq[i] = _new
                return _seq
        _seq.append(_new)
        return _seq
    except:
        _seq.append(_new)
        return _seq
def func_get_all_book_path(_username:str):
    books = []
    for root, dirs, files in os.walk("db/global/customBooks"):
        for file in files:
            if file.endswith(".csv") or file.endswith(".txt"):
                books.append(os.path.join(root, file))
    for root,dirs,files in os.walk(f"db/user/{_username}/customBooks"):
        for file in files:
            if file.endswith(".csv") or file.endswith(".txt"):
                books.append(os.path.join(root, file))
    return books

def func_main_login() -> list:
    """

    :return:
    """
    global_settings = func_read_csv_file_to_list("db/global/settings.csv")

    value = func_get_value_by_key(global_settings, "hack_protect")
    if value is None or len(value) == 0:
        fbd_login = 0.0  # 默认值
    else:
        fbd_login = float(value[0])

    now = time.time()
    if now < fbd_login:
        input(f"[x] 禁止登录!在{fbd_login - now} 秒后可登录\n按回车推出。")
        exit(0)
    registers = func_read_csv_file_to_list("db/global/userInfo.csv")
    i = 5
    stranger = ["", ""]
    while i > 0:
        if stranger[0] == "":
            stranger[0] = func_calculate_md5(input("用户名:"))
        stranger[1] = func_calculate_md5(input("密码:"))
        psw = func_get_value_by_key(registers, stranger[0])
        if psw is None:
            print("[x] 查无此人")
            if input("[?] 是否注册用户？(y/n)") == "y":  # 注册用户

                # 修改注册信息
                registers = func_change_value(registers, stranger)

                # 完善用户文件
                func_write_csv_file("db/global/userInfo.csv", registers)
                Path(f"db/user/{stranger[0]}/customBooks").mkdir(parents=True, exist_ok=True)
                func_write_csv_file(f"db/user/{stranger[0]}/settings.csv",
                                    [
                                        ["hack_protect", 1],
                                        ["level",0],
                                        ["process",[0]],
                                        ["lastBook",0],
                                        ["score",0]
                                    ])
                func_write_csv_file(f"db/user/{stranger[0]}/customBooks/error_book.csv",[[]])
                func_write_csv_file(f"db/user/{stranger[0]}/studied_book.csv",[[]])
                func_write_csv_file(f"db/user/{stranger[0]}/error_book_process.csv",[[]])
                input("[+] 注册成功！按回车继续...")

                return stranger
            stranger[0] = ""
        elif psw[0] != stranger[1]:
            print("[x] 错误的密码")
            i -= 1
        else:
            print(f"[+] 登录成功！")
            func_write_csv_file("db/global/settings.csv", func_change_value(global_settings, ["last_user", stranger[0]]))
            return stranger
    user_protect = func_get_value_by_key(
        func_read_csv_file_to_list(f"db/user/{stranger[0]}/settings.csv"),
        "hack_protect")[0]
    if user_protect == "0":
        pass
    elif user_protect == "1":
        func_write_csv_file("db/global/settings.csv",
                            func_change_value(
                                global_settings,
                                ["hack_protect", time.time() + 5 * 60]))
    elif user_protect == "2":
        func_write_csv_file("db/global/userInfo.csv",
                            func_remove_value_by_key(registers, stranger[0]))
    else:
        print("[e] 错误的保护信息")
        exit(0)
    input("[!] 多次输错密码，请重新启动程序！\n按任意键推出")
    exit(0)
#####
def func_main_words_test(_username : str):
    usersettings = func_read_csv_file_to_list(f"db/user/{_username}/settings.csv")
    last_book = func_get_value_by_key(usersettings, "lastBook")
    if last_book is None:
        last_book = "0"
    else:
        last_book = last_book[0]
    books = func_get_all_book_path(_username)
    func_clear_screen()

    print("可用书目如下：\n\t序号\t文件位置")
    for i in range(len(books)):
        print(f"\t{func_process_index(len(books),i)}\t{books[i]}")
    now_book = input(f"[>] 输入本次书目：(上次书目:{last_book})")

    if now_book == "":
        now_book = last_book
    else:
        usersettings = func_change_value(usersettings, ["lastBook", now_book])
        func_write_csv_file(f"db/user/{_username}/settings.csv",usersettings)

    final_books = []
    for i in range(-1,-len(now_book)-1,-1):
        if now_book[i] == "1":
            final_books.append(books[i])
    r = []
    for i in final_books:
        r += func_read_csv_file_to_list(i)
    func_main_words_test_handle(_username, r)


#####
def func_main_words_test_handle(_username : str, _words_list: list):
    studied_words = func_read_csv_file_to_list(f"db/user/{_username}/studied_book.csv")
    error_words = func_read_csv_file_to_list(f"db/user/{_username}/customBooks/error_book.csv")
    error_words_process = func_read_csv_file_to_list(f"db/user/{_username}/error_book_process.csv")
    usersettings = func_read_csv_file_to_list(f"db/user/{_username}/settings.csv")

    sleeptime = func_get_value_by_key(usersettings, "sleep_time")
    if sleeptime is None:
        sleeptime = 0.5
    else:
        sleeptime = float(sleeptime[0])

    random.shuffle(_words_list)
    func_clear_screen()

    s = len(studied_words)
    try:
        for i in _words_list:
            if i in studied_words:
                continue
            else:
                o = input(f"{i[1]}:(输入/exit退出)\n")
                if o == "/exit":
                    score = len(studied_words) - s
                    user_score = func_get_value_by_key(usersettings, "score")
                    if user_score is None:
                        user_score = 0
                    else:
                        user_score = int(user_score[0])
                    user_score += score
                    usersettings = func_change_value(usersettings, ["score", user_score])
                    func_write_csv_file(f"db/user/{_username}/settings.csv", usersettings)

                    func_write_csv_file(f"db/user/{_username}/studied_book.csv", studied_words)
                    func_write_csv_file(f"db/user/{_username}/customBooks/error_book.csv", error_words)
                    func_write_csv_file(f"db/user/{_username}/error_book_process.csv", error_words_process)
                    return

                print(f"你的答案:\t{o}\n正确答案:\t{i[0]}")
                if o == i[0]:
                    print("回答正确！")
                    if i not in error_words:
                        studied_words.append(i)
                    else:
                        temp = func_get_value_by_key(error_words_process, str(i))
                        if temp is None:
                            nowtime = 0
                        else:
                            nowtime = int(temp[0])
                        nowtime += 1
                        if nowtime >= 3:
                            error_words.remove(i)
                            error_words_process = func_remove_value_by_key(error_words_process, str(i))
                            studied_words.append(i)
                        else:
                            error_words_process = func_change_value(error_words_process, [str(i), nowtime])
                else:
                    print("回答错误！")
                    if i not in error_words:
                        error_words.append(i)
                    error_words_process = func_change_value(error_words_process, [str(i), 0])
                sleep(sleeptime)
                func_clear_screen()
        print("单词已学完")
    except KeyboardInterrupt:
        func_write_csv_file(f"db/user/{_username}/studied_book.csv",studied_words)
        func_write_csv_file(f"db/user/{_username}/customBooks/error_book.csv",error_words)
        func_write_csv_file(f"db/user/{_username}/error_book_process.csv",error_words_process)
        func_clear_screen()

        score = len(studied_words) - s
        usersettings = func_read_csv_file_to_list(f"db/user/{_username}/settings.csv")
        user_score = func_get_value_by_key(usersettings, "score")
        if user_score is None:
            user_score = 0
        else:
            user_score = int(user_score[0])
        user_score += score
        usersettings = func_change_value(usersettings, ["score", user_score])
        func_write_csv_file(f"db/user/{_username}/settings.csv", usersettings)
        return

#####
def func_main_user_configs(_username : str):
    usersettings = func_read_csv_file_to_list(f"db/user/{_username}/settings.csv")
    print(usersettings)
    o = input("输入对应修改选项:\n 1 \t升级\n 2 \t修改安全等级\n 3 \t修改休眠时间\n 4 \t加入单词书\n 5 \t移除单词书")
    if o == "1":
        score = func_get_value_by_key(usersettings, "score")
        if score is None:
            score = 0
        else:
            score = int(score[0])

        level = func_get_value_by_key(usersettings, "level")
        if level is None:
            level = 0
        else:
            level = int(level[0])

        process = func_get_value_by_key(usersettings, "process")
        if process is None:
            process = [0]
        else:
            process = process[0][1:-1:1].replace(" ","").split(",")
            print(process)
            target = int(input("目标等级:"))
            while score > 0:
                score -= 1
                while len(process) < target + 1:
                    process.append(0)
                process[level] = int(process[level]) + 1
                if int(process[level]) % 5 == 0 or random.random() <= 0.2:
                    level += 1
                else:
                    level = max(level - 1, 0)
                if level >= target:
                    break
            print(f"当前等级:{level}\n当前分数:{score}")
            usersettings = func_change_value(usersettings,["process", "\""+str(process)+"\""])
            usersettings = func_change_value(usersettings,["level", str(level)])
            usersettings = func_change_value(usersettings,["score", str(score)])
            func_write_csv_file(f"db/user/{_username}/settings.csv", usersettings)
            input("return...")
            return
    elif o == "2":
        s = input("输入对应安全等级(0,1,2)")
        if s not in ["0","1","2"]:
            print("ERROR")
            return
        else:
            usersettings = func_change_value(usersettings,["hack_protect", s])
            func_write_csv_file(f"db/user/{_username}/settings.csv", usersettings)
            return
    elif o == "3":
        s = input("输入休眠时间:")
        try:
            s = float(s)
            usersettings = func_change_value(usersettings,["sleep_time", s])
            func_write_csv_file(f"db/user/{_username}/settings.csv", usersettings)
            return
        except:
            print("ERROR")
            return
    elif o == "4":
        from_p = filedialog.askopenfilename(title="加入的单词书", filetypes=[("单词书（英文冒号分割）", "*.txt"),("单词书（英文逗号分隔）","*.csv"),("单词书（英文逗号分隔）","*.txt")])
        a = func_read_csv_file_to_list(from_p)
        func_write_csv_file(f"db/user/{_username}/customBooks/{from_p.split('/')[-1]}", a)
        return
    elif o == "5":
        from_p = filedialog.askopenfilename(initialdir=f"db/user/{_username}/customBooks/",title="删除的单词书", filetypes=[("单词书（英文冒号分割）", "*.txt"),("单词书（英文逗号分隔）","*.csv"),("单词书（英文逗号分隔）","*.txt")])
        try:
            os.remove(from_p)
            print("删除成功")
            sleep(1)
            return
        except:
            print("删除失败")
            sleep(1)
            return
    else:
        print("error")
        return


def func_main_log_out(_username: str):
    func_write_csv_file("db/global/settings.csv",
                        func_remove_value_by_key(func_read_csv_file_to_list("db/global/settings.csv"), "last_user"))

def func_main_delete_user(_username: str):
    try:
        if input(f"[?] 确认删除用户{_username}?(y/n)") == "y":
            func_main_log_out(_username)
            registers = func_read_csv_file_to_list("db/global/userInfo.csv")
            func_write_csv_file("db/global/userInfo.csv", func_remove_value_by_key(registers, _username))
            shutil.rmtree(f"db/user/{_username}")
            input("[-] 用户已删除\n按回车继续...")
            return
        else:
            return
    except:
        return


def func_main_get_op(_username: str):
    print(f"用户唯一存档文件夹名称：{_username}")
    try:
        func_clear_screen()
        print("[I] 0:背单词 1:用户设定配置 2:登出 3:注销")
        op = int(input("[*] 操作:"))
        func_clear_screen()
        return op
    except:
        func_clear_screen()
        return -1

def func_clear_screen():
    if platform.system() == "Windows":
        os.system('cls')
    else:
        os.system('clear')

if __name__ == "__main__":
    global_settings = func_read_csv_file_to_list("db/global/settings.csv")
    last_user = func_get_value_by_key(global_settings, "last_user")
    user_name = ''
    if last_user is None:
        user_name = func_main_login()[0]
    else:
        user_name = last_user[0]
    global_settings = func_change_value(global_settings, ["last_user", user_name])
    func_write_csv_file("db/global/settings.csv", global_settings)
    op = func_main_get_op(user_name)
    try:
        while op >= 0:
            if op == 0:
                func_main_words_test(user_name)
            elif op == 1:
                func_main_user_configs(user_name)
            elif op == 2:
                func_main_log_out(user_name)
                break
            elif op == 3:
                func_main_delete_user(user_name)
                break
            else:
                print("error")
                break
            op = func_main_get_op(user_name)
    except KeyboardInterrupt:
        func_clear_screen()
        if user_name != "":
            global_settings = func_change_value(global_settings, ["last_user", user_name])
            func_write_csv_file("db/global/settings.csv", global_settings)
    print("感谢使用")
    sleep(1.5)
